package service

import (
	"encoding/json"
	"errors"
	"strconv"
	"web_framework/config"
	"web_framework/model"
	"web_framework/pkg/constvar"
	. "web_framework/pkg/e"
	"web_framework/pkg/errno"
	"web_framework/service/lianle"
	"web_framework/storage"
)

func ValidateSN(sn string, mac string) error {

	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterInfo
	redisExi, err := storage.RedisHExists(cacheKey, "sn")
	if err != nil {
		Log("Info", "读取Redis失败", err.Error())
		return err
	}
	if redisExi == false {
		_, validaErr := lianle.ValidateSN(sn, mac)
		if validaErr != nil {
			Log("Info", errno.ErrRouterSnValidate.Info)
			return errno.ErrRouterSnValidate
		}
		_, err := storage.GetDeviceBySnMac(config.C.DB.DB, sn, mac)
		if err != nil {
			_, addErr := CreateDevice(sn, mac)
			if addErr != nil {
				Log("Info", "sn入库失败")
			}
		}
		data := map[string]interface{}{
			"sn":  sn,
			"mac": mac,
			"name": GetRouterName(sn),
		}
		_, setErr := storage.RedisHSet(cacheKey, data, constvar.TimeFormatDay)
		if setErr != nil {
			Log("Info", "sn缓存失败")
		}
	}
	routerInfo, err := storage.RedisHGetAll(cacheKey)
	if err != nil {
		Log("Info", "获取sn与mac缓存失败")
		return errors.New("获取sn与mac缓存失败")
	}
	if routerInfo["sn"] != sn || routerInfo["mac"] != mac {
		Log("Info", "sn与mac不匹配")
		return errors.New("sn与mac不匹配")
	}

	return nil
}

// 获取路由器密码
func GetRouterPassword(sn string) string {

	InitPassword := "88888888"
	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterPasswordInfo
	if storage.RedisExists(cacheKey) {
		password, err := storage.RedisGet(cacheKey)
		if err != nil {
			Log("Info", "Redis 取初始密码错误")
			return InitPassword
		}
		return password
	}else {
		data, err := lianle.STWifiInfo(sn)
		if err != nil {
			Log("Info", "调用盛天接口失败", err.Error())
			return InitPassword
		}
		return data.Key
	}
	return InitPassword
}

// 获取路由器名称
func GetRouterName(sn string) (routerName string) {

	// 取redis
	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterInfo
	redisExi, err := storage.RedisHExists(cacheKey, "sn")
	if redisExi {
		routerName, err := storage.RedisHGet(cacheKey, "name")
		if err == nil {
			return routerName
		}
	}

	// 取数据库
	router, err := storage.GetDeviceBySn(config.C.DB.DB, sn)
	if err != nil {
		routerName = "获取路由器失败2"
	}else {
		routerName = router.Name
	}
	data := map[string]interface{}{
		"name": routerName,
		"sn": router.SN,
		"mac": router.MAC,
	}

	// 写入缓存
	storage.RedisHSet(cacheKey, data, constvar.TimeFormatDay)
	return
}

// 主动刷新 WIFI信息
func GetWifiInfo(sn string, switchWifi, switchWifi5 int) (model.WifiInfo, error) {

	var wifiInfo model.WifiInfo
	data, err := lianle.STWifiInfo(sn)
	if err != nil {
		Log("Info", "调用盛天接口失败", err.Error())
		return wifiInfo, err
	}

	wifiInfoCache := make(map[string]interface{})
	wifiInfo.Password = data.Key
	wifiInfoCache["Password"] = wifiInfo.Password
	wifiInfo.SSIDName = data.SSIdName
	wifiInfoCache["SSIDName"] = wifiInfo.SSIDName
	wifiInfo.SecurityMode, _ = strconv.Atoi(data.SecurityMode)
	wifiInfoCache["SecurityMode"] = wifiInfo.SecurityMode
	wifiInfo.PrivateHideName, _ = strconv.Atoi(data.WifiEnable)
	wifiInfoCache["PrivateHideName"] = wifiInfo.PrivateHideName

	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterWIFIInfo
	// 取Redis中的开关
	if switchWifi <= 0 {
		SwitchWifi, err := storage.RedisHGet(cacheKey, "switch_wifi")
		if err != nil {
			wifiInfo.SwitchWifi = 1
		}
		wifiInfo.SwitchWifi, _ = strconv.Atoi(SwitchWifi)
		wifiInfoCache["SwitchWifi"] = wifiInfo.SwitchWifi
	}else {
		wifiInfo.SwitchWifi = switchWifi
		wifiInfoCache["SwitchWifi"] = switchWifi
	}

	if switchWifi5 <= 0 {
		SwitchWifi5, err := storage.RedisHGet(cacheKey, "switch_wifi5")
		if err != nil {
			wifiInfo.SwitchWifi5 = 1
		}
		wifiInfo.SwitchWifi5, _ = strconv.Atoi(SwitchWifi5)
		wifiInfoCache["SwitchWifi5"] = wifiInfo.SwitchWifi5
	}else {
		wifiInfo.SwitchWifi5 = switchWifi5
		wifiInfoCache["SwitchWifi5"] = switchWifi5
	}

	// 更新缓存数据
	bo, err := storage.RedisHSet(cacheKey, wifiInfoCache, constvar.TimeFormatMonth)
	if err != nil || !bo {
		Log("Info", "更新redis缓存数据失败")
		return wifiInfo, err
	}

	return wifiInfo, nil
}

// WIFI 缓存数据
func GetWifiInfoCache(sn string, switchWifi, switchWifi5 int) (model.WifiInfo, error) {

	var wifiInfo model.WifiInfo
	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterWIFIInfo
	bo, err := storage.RedisHExists(cacheKey, "SSIDName")
	if err != nil {
		Log("Info", "获取redis缓存数据失败", err.Error())
		return wifiInfo, err
	}

	if bo {
		SSIDName, err := storage.RedisHGet(cacheKey, "SSIDName")
		if err != nil {
			wifiInfo.SSIDName = "SSIDName Err"
		}
		wifiInfo.SSIDName = SSIDName

		SecurityMode, err := storage.RedisHGet(cacheKey, "SecurityMode")
		if err != nil {
			wifiInfo.SecurityMode = 1
		}
		wifiInfo.SecurityMode, _ = strconv.Atoi(SecurityMode)

		Password, err := storage.RedisHGet(cacheKey, "Password")
		if err != nil {
			wifiInfo.Password = "Password Err"
		}
		wifiInfo.Password = Password

		PrivateHideName, err := storage.RedisHGet(cacheKey, "PrivateHideName")
		if err != nil {
			wifiInfo.PrivateHideName = 1
		}
		wifiInfo.PrivateHideName, _ = strconv.Atoi(PrivateHideName)

		SwitchWifi, err := storage.RedisHGet(cacheKey, "SwitchWifi")
		if err != nil {
			wifiInfo.SwitchWifi = 1
		}
		wifiInfo.SwitchWifi, _ = strconv.Atoi(SwitchWifi)
		SwitchWifi5, err := storage.RedisHGet(cacheKey, "SwitchWifi5")
		if err != nil {
			wifiInfo.SwitchWifi5 = 1
		}
		wifiInfo.SwitchWifi5, _ = strconv.Atoi(SwitchWifi5)
		return wifiInfo, nil
	}

	wifiInfo, err = GetWifiInfo(sn, switchWifi, switchWifi5)
	if err != nil {
		return wifiInfo, err
	}

	return wifiInfo, nil
}

// 主动刷新 缓存数据
func GetDeviceUserBind(uid int) ([]model.Router, error)  {

	// 去数据库取值
	bind, err := storage.GetDeviceUserBindByUid(config.C.DB.DB, uid)
	if err != nil {
		Log("Info", err.Error())
		return bind, err
	}
	// 放入redis
	var reply []byte
	bindKey := constvar.RedisDeviceBind + strconv.Itoa(uid)
	if len(bind) > 0 {
		reply, err = json.Marshal(bind)
		if err != nil {
			Log("Info", "解析数据失败", err.Error())
			return bind, err
		}
	}
	bo, err := storage.RedisSet(bindKey, reply, constvar.RedisExpireMinute30)
	if bo && err == nil {
		Log("Info", "Redis 获取失败")
		return bind, nil
	}
	return bind, nil
}

func GetDeviceUserBindCache(uid int) ([]model.Router, error) {

	var err error
	var find []byte
	var bind []model.Router
	bindKey := constvar.RedisDeviceBind + strconv.Itoa(uid)
	if storage.RedisExists(bindKey) {
		findData, err := storage.RedisGetList(bindKey)
		err = json.Unmarshal(findData, &bind)
		if err != nil {
			Log("Info", "数据解析失败", err.Error())
			return bind, err
		}
		return bind, nil
	}
	if len(find) < 1 {
		// 去数据库取值
		bind, err = GetDeviceUserBind(uid)
		if err != nil {
			Log("Info", "取DB数据失败", err.Error())
			return bind, err
		}
	}

	return bind, nil
}

// 一个设备只能一个用户绑定
func CheckDeviceBind(sn string, uid int) (bool, error) {

	db := config.C.DB.DB
	user, err := storage.GetDeviceBindBySn(db, sn)
	if err != nil {
		Log("Info", "取DB数据失败", err.Error())
		return false, err
	}

	var version string
	if user.DeviceID.Valid {
		// 存在记录不需要 请求盛天接口
		if user.BindID.Valid == false {
			// 不存在绑定关系 直接绑定
			err = storage.BindDeviceUser(db, user.DeviceID.Int64, int64(uid))
			if err != nil {
				Log("Info", errno.ErrDeviceBindFail.Info)
				return false, errno.ErrDeviceBindFail
			}
		}else {
			if user.Status.Valid && user.Status.Int64 != 20 {
				Log("Info", errno.ErrDeviceBind.Info)
				return false, errno.ErrDeviceBind
			}
			err = storage.UpdateBindDevice(db, int(user.BindID.Int64), uid)
			if err != nil {
				Log("Info", errno.ErrDeviceBindFail.Info)
				return false, errno.ErrDeviceBindFail
			}
		}
		// 绑定的时候需要重写redis数据
		mapData := make(map[string]interface{}, 5)
		baseRouterInfoKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterInfo
		mapData["sn"] = sn
		mapData["mac"] = user.MAC.String
		mapData["route_version"] = "1.0.5.113"
		mapData["share_model"] = 0
		mapData["name"] = user.NAME.String
		storage.RedisHSet(baseRouterInfoKey, mapData, -1)
	}else {
		// 不存在记录  请求盛天接口
		dd, err := lianle.STVersion(sn)
		if err != nil {
			Log("Info", "调用盛天接口失败", err.Error())
			return false, err
		}
		if dd.VersionTo != "" {
			version =  dd.VersionTo
		}else {
			version =  dd.VersionFrom
		}
		// 先插入设备表 再插入绑定关系表
		deviceID, err := CreateDevice(sn, "")
		if err != nil {
			Log("Info", "插入数据库失败", err.Error())
			return  false, err
		}
		err = storage.BindDeviceUser(db, int64(deviceID), int64(uid))
		if err != nil {
			Log("Info", "绑定用户关系失败", err.Error())
			return  false, err
		}

		// 从盛天接口获取 最新的路由器信息写入redis
		deviceInfo, err := lianle.STWifiInfo(sn)
		if err == nil {
			mapData := make(map[string]interface{}, 5)
			baseRouterInfoKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterInfo
			mapData["sn"] = deviceInfo.Sn
			mapData["mac"] = deviceInfo.Mac
			mapData["route_version"] = version
			mapData["share_model"] = 0
			mapData["name"] = deviceInfo.SSIdName
			storage.RedisHSet(baseRouterInfoKey, mapData, -1)
		}
	}

	// 刷新缓存数据
	Log("Info", "刷新用户绑定设备信息数据缓存")
	GetDeviceUserBind(uid)

	return true, nil
}

// 解绑用户
func DeviceUnbind(uid int, sn string) error {

	Log("Info", "DeviceUnbind Uid:", uid, " sn: ", sn)
	db := config.C.DB.DB
	router, err := storage.GetDeviceBySn(db, sn)
	if err != nil || router.DeviceID <= 0 {
		Log("Info", "取DB数据失败", errno.ErrDeviceFound.Info)
		return errno.ErrDeviceFound
	}

	reply, err := storage.GetDeviceBySnDeviceId(db, uid, router.DeviceID)
	if err != nil || reply.BindID <= 0 {
		Log("Info", "取DB数据失败", errno.ErrDeviceValidate.Info)
		return errno.ErrDeviceValidate
	}

	if reply.Status == 20 {
		Log("Info", errno.ErrDeviceUnBind.Info)
		return errno.ErrDeviceUnBind
	}

	err = storage.UpdateUnbindDevice(db, reply.BindID)
	if err != nil {
		Log("Info", "解绑路由器失败", err.Error())
		return err
	}

	// 刷新缓存数据
	_, err = GetDeviceUserBind(uid)
	if err != nil {
		Log("Info", "刷新缓存数据失败", err.Error())
		return err
	}
	return nil
}

// 获取上一次 速度限制
func GetSpeedLimit(sn string) (model.LimitSpeed, error) {

	Log("Info", "调用方法")

	var limitSpeed model.LimitSpeed
	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterLimitSpeed
	bo, err := storage.RedisHExists(cacheKey, "upspeed")
	if err != nil {
		Log("Info", "取Redis数据失败", err.Error())
		return limitSpeed, err
	}
	if bo {
		UpSpeed, err := storage.RedisHGet(cacheKey, "upspeed")
		if err != nil {
			Log("Info", "取Redis数据失败", err.Error())
			return limitSpeed, err
		}
		limitSpeed.UpSpeed, err = strconv.ParseFloat(UpSpeed, 64)
		if err != nil {
			Log("Info", "数据格式转化失败", err.Error())
			return limitSpeed, err
		}
	}

	bo, err = storage.RedisHExists(cacheKey, "downspeed")
	if err != nil {
		Log("Info", "取Redis数据失败", err.Error())
		return limitSpeed, err
	}
	if bo {
		DownSpeed, err := storage.RedisHGet(cacheKey, "downspeed")
		if err != nil {
			Log("Info", "取Redis数据失败", err.Error())
			return limitSpeed, err
		}
		limitSpeed.DownSpeed, err = strconv.ParseFloat(DownSpeed, 64)
		if err != nil {
			Log("Info", "数据格式转化失败", err.Error())
			return limitSpeed, err
		}
	}

	return limitSpeed, nil
}

// 设置速度限制
func SetSpeedLimit(sn string, upSpeed, downSpeed float64) error {

	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterLimitSpeed
	var data = make(map[string]interface{})
	if upSpeed == -1 && downSpeed == -1 {
		return nil
	}
	if upSpeed >= 0 {
		data["upspeed"] = upSpeed
	}
	if downSpeed >= 0 {
		data["downspeed"] = downSpeed
	}
	bo, err := storage.RedisHSet(cacheKey, data, -1)
	if err != nil || !bo {
		Log("Info", "写入Redis失败", err.Error())
		return err
	}

	return nil
}

// 路由器设置
func WifiSetting(sn, SSidName, key, wifiEnable, securityMode string) error {

	err := lianle.STSettingUpdate(sn, SSidName, key, wifiEnable, securityMode)
	if err != nil {
		Log("Info", "调用盛天接口失败", err.Error())
		return err
	}

	GetWifiInfo(sn, 0, 0)
	return nil
}

// 根据路由器绑定sn mac
func CreateDevice(sn, mac string) (int, error) {

	Log("Info", "开始调用 service.CreateDevice ")
	// 根据盛天接口更新对应的路由器名称和reids数据
	data, err := lianle.STWifiInfo(sn)
	if err != nil {
		Log("Info", "调用盛天接口失败", err.Error())
		return  0, err
	}
	if mac == "" {
		mac = data.Mac
	}
	if data.Mac != mac {
		Log("Info", errno.ErrDeviceSnMac)
		return  0, errno.ErrDeviceSnMac
	}

	// 写入数据库
	name := data.SSIdName
	deviceId, err := storage.CreateDevice(config.C.DB.DB, sn, mac, name)
	if err != nil {
		Log("Info", "写入数据失败", err.Error())
		return 0, err
	}

	// 将对应的数据写入redis
	cacheKey := constvar.RouterRedisPrefix + sn + constvar.RedisRouterInfo
	redisData := map[string]interface{}{
		"name": name,
		"sn": sn,
		"mac": mac,
	}
	_, err = storage.RedisHSet(cacheKey, redisData, constvar.TimeFormatDay)
	if err != nil {
		Log("Info", "写入Redis失败", err.Error())
		return deviceId, err
	}

	return deviceId, nil
}